package org.paradigmshift.timelapse.ui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.CellRendererPane;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

@SuppressWarnings( "serial" )
public class BetterJTable extends JTable {

	public static final Color TABLE_GRID_COLOR = new Color( 0xd9d9d9 );

	private static final CellRendererPane CELL_RENDER_PANE = new CellRendererPane();
	
	public BetterJTable( TableModel dm ) {

		super( dm );
		init();
	}

	private void init() {
		
		setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
		
		setTableHeader( createTableHeader() );
		setAutoCreateRowSorter( true );
		if ( OSValidator.isMac() ) {
			getTableHeader().addMouseListener( new MouseListener() {

				@Override
				public void mouseClicked( MouseEvent e ) {
					getTableHeader().putClientProperty( "JTableHeader.selectedColumn", getTableHeader().columnAtPoint( e.getPoint() ) );
					if ( getTableHeader().getClientProperty( "JTableHeader.sortDirection" ) == null ) {
						getTableHeader().putClientProperty( "JTableHeader.sortDirection", "ascending" );
					}
					else if (getTableHeader().getClientProperty( "JTableHeader.sortDirection" ).equals( "ascending" ) ) {
						//misspelling is required, per Apple documentation
						getTableHeader().putClientProperty( "JTableHeader.sortDirection", "decending" );
					}
					else {
						getTableHeader().putClientProperty( "JTableHeader.sortDirection", "ascending" );
					}
				}
				
				@Override public void mousePressed( MouseEvent e ) {}
				@Override public void mouseReleased( MouseEvent e ) {}
				@Override public void mouseEntered( MouseEvent e ) {}
				@Override public void mouseExited( MouseEvent e ) {}
			} );
		}
		
		getTableHeader().setReorderingAllowed( false );
		setOpaque( false );
		setGridColor( TABLE_GRID_COLOR );
		setIntercellSpacing( new Dimension( 0, 0 ) );
		// turn off grid painting as we'll handle this manually in order to
		// paint
		// grid lines over the entire viewport.
		setShowGrid( false );
		setRowHeight( 19 );
	}
	
	/**
	 * Creates a JTableHeader that paints the table header background to the
	 * right of the right-most column if neccesasry.
	 */
	private JTableHeader createTableHeader() {

		return new JTableHeader( getColumnModel() ) {

			@Override
			protected void paintComponent( Graphics g ) {
				
				super.paintComponent( g );
				// if this JTableHEader is parented in a JViewport, then paint
				// the
				// table header background to the right of the last column if
				// neccessary.
				JViewport viewport = (JViewport) table.getParent();
				if (viewport != null && table.getWidth() < viewport.getWidth()) {
					int x = table.getWidth();
					int width = viewport.getWidth() - x;
					paintHeader( g, getTable(), x, width );
				}
			}
		};
	}

	/**
	 * Paints the given JTable's table default header background at given x for
	 * the given width.
	 */
	public static void paintHeader( Graphics g, JTable table, int x, int width ) {

		TableCellRenderer renderer = new FakeTableColumnHeaderRenderer();
		Component component = renderer.getTableCellRendererComponent( table, "", false, false, -1, -1 );

		component.setBounds( 0, 0, width, table.getTableHeader().getHeight() );

		((JComponent) component).setOpaque( false );
		CELL_RENDER_PANE.paintComponent( g, component, null, x, 0, width, table.getTableHeader().getHeight(), true );
	}

	@Override
	public Component prepareRenderer( TableCellRenderer renderer, int row, int column ) {

		Component component = super.prepareRenderer( renderer, row, column );
		// if the rendere is a JComponent and the given row isn't part of a
		// selection, make the renderer non-opaque so that striped rows show
		// through.
		if (component instanceof JComponent) {
			((JComponent) component).setOpaque( getSelectionModel().isSelectedIndex( row ) );
		}
		return component;
	}
}
